#if 1
/*
 * main.c
 *
 *  Created on: 2023闁跨喐鏋婚幏锟�4闁跨喐鏋婚幏锟�14闁跨喐鏋婚幏锟�
 *      Author: hello
 */


#include "bsdiff.h"
#include "bspatch.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "memheap.h"
#include "lzma_port.h"
#include "LzmaEnc.h"
#include "LzmaDec.h"
#include "LzmaUtil.h"
#include "iap_bspatch.h"

int getfilesize(const char* fname);
int loadfile(const char* filename, uint8_t* buf);
int storefile(const char* filename, uint8_t* buf, uint32_t len);
int readfile(const char* fname, uint32_t offset, void* buf, uint32_t len);
int writefile(const char* fname, uint32_t offset, void* buf, uint32_t len);

#define debug(fmt,...) do{printf(fmt, ##__VA_ARGS__);fflush(stdout);}while(0)

static int writepatch(struct bsdiff_stream* stream, const void* buffer, int size)
{
	FILE* fp = (FILE*)stream->opaque;
	if(fwrite(buffer, 1, size, fp) != size)
		return -1;
	return 0;
}

void genpatch(const char* fnameold, const char* fnamenew, const char* fnamepatch)
{
	uint8_t *old,*new;
	off_t oldsize,newsize;
	uint8_t buf[8];
	FILE * pf;
	struct bsdiff_stream stream;

	stream.malloc = malloc;
	stream.free = free;
	stream.write = writepatch;

	oldsize = getfilesize(fnameold);
	newsize = getfilesize(fnamenew);

	old = malloc(oldsize + 1);
	new = malloc(newsize + 1);

	if(loadfile(fnameold, old) < 0 ||  loadfile(fnamenew, new) < 0)
	{
		debug("Failed to load file \n");
		goto __exit;
	}

	/* Create the patch file */
	pf = fopen(fnamepatch, "wb+");
	if(!pf)
	{
		debug("Failed to create patch file \n");
		goto __exit;
	}

	/* Write header (signature+newsize)*/
	offtout(newsize, buf);
	if (fwrite("ENDSLEY/BSDIFF43", 16, 1, pf) != 1 || fwrite(buf, sizeof(buf), 1, pf) != 1)
	{
		debug("Failed to write header \n");
		goto __exit;
	}

	stream.opaque = pf;
	if (bsdiff(old, oldsize, new, newsize, &stream))
	{
		debug("Failed to bsdiff \n");
		goto __exit;
	}

	debug(" generate patch successfully ! \n");

__exit:

	fclose(pf);

	/* Free the memory we used */
	free(old);
	free(new);
}

static int readpatch(const struct bspatch_stream* stream, void* buffer, int length)
{
	FILE* fp = (FILE*)stream->opaque;
	if(fread(buffer, 1, length, fp) != length)
		return -1;
	return 0;
}

void restorenew(const char* fnameold, const char* fnamepatch, const char* fnamenew)
{
	FILE * f;
	uint8_t header[24];
	uint8_t *old, *new;
	int64_t oldsize, newsize;
	struct bspatch_stream stream;

	/* Open patch file */
	if ((f = fopen(fnamepatch, "r")) == NULL)
	{
		debug(" Failed to open patch file ");
		goto __exit;
	}

	/* Read header */
	if (fread(header, 1, 24, f) != 24)
	{
		debug(" Failed to read patch header ");
		goto __exit;
	}

	/* Check for appropriate magic */
	if (memcmp(header, "ENDSLEY/BSDIFF43", 16) != 0)
	{
		debug(" Corrupt patch file ");
		goto __exit;
	}

	/* Read lengths from header */
	newsize=offtin(header+16);
	if(newsize<0)
	{
		debug(" Corrupt patch file ");
		goto __exit;
	}

	oldsize = getfilesize(fnameold);

	if(oldsize < 0)
	{
		debug("Failed to get old file size \n");
		goto __exit;
	}

	old = malloc(oldsize + 1);
	new = malloc(newsize + 1);

	if(loadfile(fnameold, old) < 0)
	{
		debug("Failed to read old file \n");
		goto __exit;
	}

	stream.read = readpatch;
	stream.opaque = f;
	if (bspatch(old, oldsize, new, newsize, &stream))
	{
		debug(" Failed to bspatch \n");
		goto __exit;
	}

	if(storefile(fnamenew, new, newsize) < 0)
	{
		debug(" Failed to save new file \n");
		goto __exit;
	}

	debug(" restore new file successfully ! \n");

__exit:
	fclose(f);
	free(new);
	free(old);
}

static int lzma_readpatch(const struct bspatch_stream* stream, void* buffer, int length)
{
	if(lzma_uncompress_read((lzma_dec_t *)stream->opaque, buffer, length) < 0)
		return -1;
	return 0;
}

void restorenew2(const char* fnameold, const char* fnamepatch, const char* fnamenew)
{
	uint8_t header[24];
	uint8_t *old, *new;
	int64_t oldsize, newsize;
	struct bspatch_stream stream;
	lzma_dec_t dec;

	if(lzma_uncompress_init(&dec, fnamepatch) < 0)
	{
		debug(" Failed to init uncompressor \n");
		goto __exit;
	}

	/* Read header */
	if (lzma_uncompress_read(&dec, header, 24) < 0)
	{
		debug(" Failed to read patch header ");
		goto __exit;
	}

	/* Check for appropriate magic */
	if (memcmp(header, "ENDSLEY/BSDIFF43", 16) != 0)
	{
		debug(" Corrupt patch file ");
		goto __exit;
	}

	/* Read lengths from header */
	newsize=offtin(header+16);
	if(newsize<0)
	{
		debug(" Corrupt patch file ");
		goto __exit;
	}

	oldsize = vfsize(fnameold);
	if(oldsize == 0)
	{
		debug("Failed to get old file size \n");
		goto __exit;
	}

	old = malloc(oldsize + 1);
	new = malloc(newsize + 1);

	if(loadfile(fnameold, old) < 0)
	{
		debug("Failed to read old file \n");
		goto __exit;
	}

	stream.read = lzma_readpatch;
	stream.opaque = &dec;
	if (bspatch(old, oldsize, new, newsize, &stream))
	{
		debug(" Failed to bspatch \n");
		goto __exit;
	}

	if(storefile(fnamenew, new, newsize) < 0)
	{
		debug(" Failed to save new file \n");
		goto __exit;
	}

	debug(" restore new file successfully ! \n");

__exit:
	lzma_uncompress_destory(&dec);
	free(new);
	free(old);
}

int main(int argc,char *argv[])
{
	// 初始化内存堆
	memheap_init();

	// 生成差异补丁文件
	genpatch("old.bin", "new.bin", "patch.diff");

	// 压缩差异补丁文件
	lzma_compress("patch.diff", "patch.lzma");

	// 解压缩差异补丁文件
	lzma_uncompress("patch.lzma", "patch-uncompress.diff");

	// 根据未压缩的差异补丁文件还原新文件
	restorenew("old.bin", "patch-uncompress.diff", "new-restore.bin");

	// 根据差异补丁文件还原新文件
	restorenew2("old.bin", "patch.lzma", "new-restore2.bin");
//	iap_bspatch("old.bin", "patch.lzma", "new-restore.bin");
	return 0;
}

int loadfile(const char* filename, uint8_t* buf)
{
	int filesize = 0, nread = 0;
	FILE* fp = NULL;
	fp = fopen(filename, "rb");
	if(!fp)
		return -1;
	fseek(fp, 0, SEEK_END);
	filesize = ftell(fp);
	fseek(fp, 0, SEEK_SET);
	if(filesize > 0)
		nread = fread(buf, 1, filesize, fp);
	fclose(fp);
	return nread;
}

int storefile(const char* filename, uint8_t* buf, uint32_t len)
{
	int nwrite = 0;
	FILE* fp = NULL;
	fp = fopen(filename, "wb+");
	if(!fp)
	{
		return -1;
	}
	nwrite = fwrite(buf, 1, len, fp);
	fclose(fp);
	return nwrite;
}

int readfile(const char* fname, uint32_t offset, void* buf, uint32_t len)
{
	int nread = 0;
	FILE* fp = NULL;
	fp = fopen(fname, "rb");
	if(!fp)
		return -1;
	fseek(fp, offset, SEEK_SET);
	nread = fread(buf, 1, len, fp);
	fclose(fp);
	return nread;
}

int writefile(const char* fname, uint32_t offset, void* buf, uint32_t len)
{
	int nwrite = 0;
	FILE* fp = NULL;
	fp = fopen(fname, "ab");
	if(!fp)
		return -1;
	fseek(fp, offset, SEEK_SET);
	nwrite = fwrite(buf, 1, len, fp);
	fclose(fp);
	return nwrite;
}

int getfilesize(const char* fname)
{
	int len = 0;
	FILE* fp = NULL;
	fp = fopen(fname, "r");
	if(!fp)
		return -1;
	fseek(fp, 0, SEEK_END);
	len = ftell(fp);
	fclose(fp);
	return len;
}
#endif
